// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.ai;

import java.util.ArrayDeque;
import java.util.ArrayList;
import zombie.ai.states.PathFindState;
import zombie.ai.states.WalkTowardState;
import zombie.ai.states.ZombieIdleState;
import zombie.characters.IsoPlayer;
import zombie.characters.IsoZombie;
import zombie.characters.ZombieGroup;
import zombie.core.Core;
import zombie.core.Rand;
import zombie.iso.IsoCell;
import zombie.iso.IsoGridSquare;
import zombie.iso.IsoMetaGrid;
import zombie.iso.IsoMovingObject;
import zombie.iso.IsoUtils;
import zombie.iso.IsoWorld;
import zombie.iso.Vector2;
import zombie.iso.Vector3;
import zombie.network.GameClient;
import zombie.network.GameServer;

public final class ZombieGroupManager {
    public static final ZombieGroupManager instance = new ZombieGroupManager();
    private final ArrayList<ZombieGroup> groups = new ArrayList();
    private final ArrayDeque<ZombieGroup> freeGroups = new ArrayDeque();
    private final Vector2 tempVec2 = new Vector2();
    private final Vector3 tempVec3 = new Vector3();
    private float tickCount = 30.0F;

    public void preupdate() {
        this.tickCount = this.tickCount + zombie.GameTime.getInstance().getMultiplier() / 1.6F;
        if (this.tickCount >= 30.0F) {
            this.tickCount = 0.0F;
        }

        int int0 = zombie.SandboxOptions.instance.zombieConfig.RallyGroupSize.getValue();

        for (int int1 = 0; int1 < this.groups.size(); int1++) {
            ZombieGroup zombieGroup = (ZombieGroup)this.groups.get(int1);
            zombieGroup.update();
            if (zombieGroup.isEmpty()) {
                this.freeGroups.push(zombieGroup);
                this.groups.remove(int1--);
            }
        }
    }

    public void Reset() {
        this.freeGroups.addAll(this.groups);
        this.groups.clear();
    }

    public boolean shouldBeInGroup(IsoZombie zombie) {
        if (zombie == null) {
            return false;
        } else if (zombie.SandboxOptions.instance.zombieConfig.RallyGroupSize.getValue() <= 1) {
            return false;
        } else if (!Core.getInstance().isZombieGroupSound()) {
            return false;
        } else if (zombie.isUseless()) {
            return false;
        } else if (zombie.isDead() || zombie.isFakeDead()) {
            return false;
        } else if (zombie.isSitAgainstWall()) {
            return false;
        } else if (zombie.target != null) {
            return false;
        } else if (zombie.getCurrentBuilding() != null) {
            return false;
        } else if (zombie.VirtualZombieManager.instance.isReused(zombie)) {
            return false;
        } else {
            IsoGridSquare isoGridSquare = zombie.getSquare();
            IsoMetaGrid.Zone zone = isoGridSquare == null ? null : isoGridSquare.getZone();
            return zone == null || !"Forest".equals(zone.getType()) && !"DeepForest".equals(zone.getType());
        }
    }

    public void update(IsoZombie zombie) {
        if (!GameClient.bClient || !zombie.isRemoteZombie()) {
            if (!this.shouldBeInGroup(zombie)) {
                if (zombie.group != null) {
                    zombie.group.remove(zombie);
                }
            } else if (this.tickCount == 0.0F) {
                if (zombie.group == null) {
                    ZombieGroup zombieGroup0 = this.findNearestGroup(zombie.getX(), zombie.getY(), zombie.getZ());
                    if (zombieGroup0 == null) {
                        zombieGroup0 = this.freeGroups.isEmpty() ? new ZombieGroup() : ((ZombieGroup)this.freeGroups.pop()).reset();
                        zombieGroup0.add(zombie);
                        this.groups.add(zombieGroup0);
                        return;
                    }

                    zombieGroup0.add(zombie);
                }

                if (zombie.getCurrentState() == ZombieIdleState.instance()) {
                    if (zombie == zombie.group.getLeader()) {
                        float float0 = (float)zombie.GameTime.getInstance().getWorldAgeHours();
                        zombie.group.lastSpreadOutTime = Math.min(zombie.group.lastSpreadOutTime, float0);
                        if (!(zombie.group.lastSpreadOutTime + 0.083333336F > float0)) {
                            zombie.group.lastSpreadOutTime = float0;
                            int int0 = zombie.SandboxOptions.instance.zombieConfig.RallyGroupSeparation.getValue();
                            Vector2 vector2 = this.tempVec2.set(0.0F, 0.0F);

                            for (int int1 = 0; int1 < this.groups.size(); int1++) {
                                ZombieGroup zombieGroup1 = (ZombieGroup)this.groups.get(int1);
                                if (zombieGroup1.getLeader() != null
                                    && zombieGroup1 != zombie.group
                                    && (int)zombieGroup1.getLeader().getZ() == (int)zombie.getZ()) {
                                    float float1 = zombieGroup1.getLeader().getX();
                                    float float2 = zombieGroup1.getLeader().getY();
                                    float float3 = IsoUtils.DistanceToSquared(zombie.x, zombie.y, float1, float2);
                                    if (!(float3 > (float)(int0 * int0))) {
                                        vector2.x = vector2.x - float1 + zombie.x;
                                        vector2.y = vector2.y - float2 + zombie.y;
                                    }
                                }
                            }

                            int int2 = this.lineClearCollideCount(
                                zombie,
                                zombie.getCell(),
                                (int)(zombie.x + vector2.x),
                                (int)(zombie.y + vector2.y),
                                (int)zombie.z,
                                (int)zombie.x,
                                (int)zombie.y,
                                (int)zombie.z,
                                10,
                                this.tempVec3
                            );
                            if (int2 >= 1) {
                                if (GameClient.bClient || GameServer.bServer || !(IsoPlayer.getInstance().getHoursSurvived() < 2.0)) {
                                    if (!(this.tempVec3.x < 0.0F)
                                        && !(this.tempVec3.y < 0.0F)
                                        && IsoWorld.instance.MetaGrid.isValidChunk((int)this.tempVec3.x / 10, (int)this.tempVec3.y / 10)) {
                                        zombie.pathToLocation((int)(this.tempVec3.x + 0.5F), (int)(this.tempVec3.y + 0.5F), (int)this.tempVec3.z);
                                        if (zombie.getCurrentState() == PathFindState.instance() || zombie.getCurrentState() == WalkTowardState.instance()) {
                                            zombie.setLastHeardSound(zombie.getPathTargetX(), zombie.getPathTargetY(), zombie.getPathTargetZ());
                                            zombie.AllowRepathDelay = 400.0F;
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        float float4 = zombie.group.getLeader().getX();
                        float float5 = zombie.group.getLeader().getY();
                        int int3 = zombie.SandboxOptions.instance.zombieConfig.RallyGroupRadius.getValue();
                        if (!(IsoUtils.DistanceToSquared(zombie.x, zombie.y, float4, float5) < (float)(int3 * int3))) {
                            if (GameClient.bClient || GameServer.bServer || !(IsoPlayer.getInstance().getHoursSurvived() < 2.0) || Core.bDebug) {
                                int int4 = (int)(float4 + (float)Rand.Next(-int3, int3));
                                int int5 = (int)(float5 + (float)Rand.Next(-int3, int3));
                                if (int4 >= 0 && int5 >= 0 && IsoWorld.instance.MetaGrid.isValidChunk(int4 / 10, int5 / 10)) {
                                    zombie.pathToLocation(int4, int5, (int)zombie.group.getLeader().getZ());
                                    if (zombie.getCurrentState() == PathFindState.instance() || zombie.getCurrentState() == WalkTowardState.instance()) {
                                        zombie.setLastHeardSound(zombie.getPathTargetX(), zombie.getPathTargetY(), zombie.getPathTargetZ());
                                        zombie.AllowRepathDelay = 400.0F;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public ZombieGroup findNearestGroup(float x, float y, float z) {
        ZombieGroup zombieGroup0 = null;
        float float0 = Float.MAX_VALUE;
        int int0 = zombie.SandboxOptions.instance.zombieConfig.RallyTravelDistance.getValue();

        for (int int1 = 0; int1 < this.groups.size(); int1++) {
            ZombieGroup zombieGroup1 = (ZombieGroup)this.groups.get(int1);
            if (zombieGroup1.isEmpty()) {
                this.groups.remove(int1--);
            } else if ((int)zombieGroup1.getLeader().getZ() == (int)z
                && zombieGroup1.size() < zombie.SandboxOptions.instance.zombieConfig.RallyGroupSize.getValue()) {
                float float1 = IsoUtils.DistanceToSquared(x, y, zombieGroup1.getLeader().getX(), zombieGroup1.getLeader().getY());
                if (float1 < (float)(int0 * int0) && float1 < float0) {
                    float0 = float1;
                    zombieGroup0 = zombieGroup1;
                }
            }
        }

        return zombieGroup0;
    }

    private int lineClearCollideCount(
        IsoMovingObject isoMovingObject, IsoCell isoCell, int int5, int int2, int int8, int int6, int int3, int int9, int int12, Vector3 vector3
    ) {
        int int0 = 0;
        int int1 = int2 - int3;
        int int4 = int5 - int6;
        int int7 = int8 - int9;
        float float0 = 0.5F;
        float float1 = 0.5F;
        IsoGridSquare isoGridSquare0 = isoCell.getGridSquare(int6, int3, int9);
        vector3.set((float)int6, (float)int3, (float)int9);
        if (Math.abs(int4) > Math.abs(int1) && Math.abs(int4) > Math.abs(int7)) {
            float float2 = (float)int1 / (float)int4;
            float float3 = (float)int7 / (float)int4;
            float0 += (float)int3;
            float1 += (float)int9;
            int4 = int4 < 0 ? -1 : 1;
            float2 *= (float)int4;
            float3 *= (float)int4;

            while (int6 != int5) {
                int6 += int4;
                float0 += float2;
                float1 += float3;
                IsoGridSquare isoGridSquare1 = isoCell.getGridSquare(int6, (int)float0, (int)float1);
                if (isoGridSquare1 != null && isoGridSquare0 != null) {
                    boolean boolean0 = isoGridSquare1.testCollideAdjacent(
                        isoMovingObject,
                        isoGridSquare0.getX() - isoGridSquare1.getX(),
                        isoGridSquare0.getY() - isoGridSquare1.getY(),
                        isoGridSquare0.getZ() - isoGridSquare1.getZ()
                    );
                    if (boolean0) {
                        return int0;
                    }
                }

                isoGridSquare0 = isoGridSquare1;
                int int10 = (int)float0;
                int int11 = (int)float1;
                vector3.set((float)int6, (float)int10, (float)int11);
                if (++int0 >= int12) {
                    return int0;
                }
            }
        } else if (Math.abs(int1) >= Math.abs(int4) && Math.abs(int1) > Math.abs(int7)) {
            float float4 = (float)int4 / (float)int1;
            float float5 = (float)int7 / (float)int1;
            float0 += (float)int6;
            float1 += (float)int9;
            int1 = int1 < 0 ? -1 : 1;
            float4 *= (float)int1;
            float5 *= (float)int1;

            while (int3 != int2) {
                int3 += int1;
                float0 += float4;
                float1 += float5;
                IsoGridSquare isoGridSquare2 = isoCell.getGridSquare((int)float0, int3, (int)float1);
                if (isoGridSquare2 != null && isoGridSquare0 != null) {
                    boolean boolean1 = isoGridSquare2.testCollideAdjacent(
                        isoMovingObject,
                        isoGridSquare0.getX() - isoGridSquare2.getX(),
                        isoGridSquare0.getY() - isoGridSquare2.getY(),
                        isoGridSquare0.getZ() - isoGridSquare2.getZ()
                    );
                    if (boolean1) {
                        return int0;
                    }
                }

                isoGridSquare0 = isoGridSquare2;
                int int13 = (int)float0;
                int int14 = (int)float1;
                vector3.set((float)int13, (float)int3, (float)int14);
                if (++int0 >= int12) {
                    return int0;
                }
            }
        } else {
            float float6 = (float)int4 / (float)int7;
            float float7 = (float)int1 / (float)int7;
            float0 += (float)int6;
            float1 += (float)int3;
            int7 = int7 < 0 ? -1 : 1;
            float6 *= (float)int7;
            float7 *= (float)int7;

            while (int9 != int8) {
                int9 += int7;
                float0 += float6;
                float1 += float7;
                IsoGridSquare isoGridSquare3 = isoCell.getGridSquare((int)float0, (int)float1, int9);
                if (isoGridSquare3 != null && isoGridSquare0 != null) {
                    boolean boolean2 = isoGridSquare3.testCollideAdjacent(
                        isoMovingObject,
                        isoGridSquare0.getX() - isoGridSquare3.getX(),
                        isoGridSquare0.getY() - isoGridSquare3.getY(),
                        isoGridSquare0.getZ() - isoGridSquare3.getZ()
                    );
                    if (boolean2) {
                        return int0;
                    }
                }

                isoGridSquare0 = isoGridSquare3;
                int int15 = (int)float0;
                int int16 = (int)float1;
                vector3.set((float)int15, (float)int16, (float)int9);
                if (++int0 >= int12) {
                    return int0;
                }
            }
        }

        return int0;
    }
}
